home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / comm2 / kms20src.lha / KMSC / areas.c < prev    next >
C/C++ Source or Header  |  1994-08-14  |  46KB  |  1,696 lines

  1. /**********************************
  2.  *              KMS               *
  3.  **********************************
  4.  *  ©1992 by BlackMagic Software  *
  5.  **********************************
  6.  *                                *
  7.  **********************************/
  8.  
  9. #include <KMS/KMS.h>
  10.  
  11. Prototype struct AreaNode *SetArea(UWORD);
  12. Prototype UMSMsgNum SelectArea(STRPTR);
  13. Prototype struct AreaNode *InsertArea(VOID);
  14. Prototype VOID DeleteArea(struct AreaNode *);
  15. Prototype BOOL EditArea(STRPTR, UWORD);
  16. Prototype BOOL EditAreaInfo(struct AreaNode *);
  17. Prototype BOOL RemoveArea(STRPTR);
  18. Prototype BOOL ListAreas(STRPTR, UWORD);
  19. Prototype BOOL PrintAreaInfo(struct AreaNode *, UBYTE);
  20. Prototype BOOL ChangePath(STRPTR);
  21. Prototype VOID CreatePath(struct AreaNode *);
  22. Prototype struct AreaNode *ChangeArea(STRPTR);
  23. Prototype STRPTR PathParse(STRPTR, STRPTR);
  24. Prototype struct AreaNode *SeekAreaName(struct AreaNode *, STRPTR);
  25. Prototype struct AreaNode *AreaSearch(STRPTR);
  26. Prototype BOOL AreaModify(STRPTR, UWORD);
  27. Prototype BOOL GlobalAreaChange(STRPTR, UWORD, UWORD, ULONG);
  28. Prototype VOID TakeASem(BOOL);
  29. Prototype VOID DropASem(VOID);
  30.  
  31. /*****************************
  32.  * Externe Globale Variablen *
  33.  *****************************/
  34.  
  35. extern struct KMSBase *KMSBase;
  36. extern struct LocalConfig *KMS_LC;
  37.  
  38. extern UMSAccount MyUMSAccount;
  39.  
  40. extern STRPTR PPArg, PPArg2;
  41.  
  42. extern UBYTE ShutDown, Plop;
  43.  
  44. /*********************
  45.  * Globale Variablen *
  46.  *********************/
  47.  
  48. TEXT PathString[LEN_KMSPATH+1];
  49.  
  50. /********************************
  51.  * Area in Liste suchen         *
  52.  * TakeASem() von außen nötig!  *
  53.  ********************************
  54.  * I: Area-Index                *
  55.  * O: struct AreaNode *         *
  56.  ********************************/
  57.  
  58. /// "SetArea"
  59.  
  60. struct AreaNode *SetArea(UWORD idx)
  61.    {
  62.    struct AreaNode *apoint;
  63.    UWORD startidx = 0;
  64.    BOOL forward = TRUE;
  65.  
  66.    if (!idx)
  67.       return NULL;
  68.  
  69.    apoint = (struct AreaNode *)KMSBase->AreaList.mlh_Head;
  70.  
  71.    if (KMS_LC->Session.CurrentArea)
  72.       {
  73.       startidx = KMS_LC->Session.CurrentArea->AreaData.ID;
  74.       apoint = KMS_LC->Session.CurrentArea;
  75.       }
  76.  
  77.    if (idx == startidx)
  78.       return KMS_LC->Session.CurrentArea;
  79.  
  80.    if (idx < startidx)
  81.       forward = FALSE;
  82.  
  83.    if (apoint->Node.mln_Succ)
  84.       {
  85.       while(((forward && apoint->Node.mln_Succ) || (!forward && apoint->Node.mln_Pred)) && apoint->AreaData.ID != idx)
  86.          {
  87.          if (forward)
  88.             apoint = (struct AreaNode *)apoint->Node.mln_Succ;
  89.          else
  90.             apoint = (struct AreaNode *)apoint->Node.mln_Pred;
  91.          }
  92.  
  93.       if (apoint->Node.mln_Succ && apoint->Node.mln_Pred)
  94.          return apoint;
  95.       else
  96.          return NULL;
  97.       }
  98.    else
  99.       {
  100.       SystemError("SetArea", "No AreaList!");
  101.       return NULL;
  102.       }
  103.    }
  104.  
  105. ///
  106.  
  107. /**************************************
  108.  * Group-Flag in Area "mbname" setzen *
  109.  **************************************
  110.  * I: MsgBase-Name                    *
  111.  * O: Anzahl Msgs in Gruppe           *
  112.  **************************************/
  113.  
  114. /// "SelectArea"
  115.  
  116. UMSMsgNum SelectArea(STRPTR mbname)
  117.    {
  118.    UMSMsgNum result;
  119.  
  120.    /* Alle gesetzten Local-Flag 2 rücksetzen */
  121.  
  122.    UMSSelectTags(MyUMSAccount, UMSTAG_SelReadLocal,  TRUE,
  123.                              UMSTAG_SelMask,       KMSLSTATF_InGroup,
  124.                              UMSTAG_SelMatch,      KMSLSTATF_InGroup,
  125.                              UMSTAG_SelWriteLocal, TRUE,
  126.                              UMSTAG_SelUnset,      KMSLSTATF_InGroup,
  127.                              TAG_DONE);
  128.  
  129.    /* Alle Nachrichten der aktuellen Gruppe für den User
  130.       mit Local-Flag 2 markieren                         */
  131.  
  132.    if (!strcmp(mbname, "*KMS-GLOBAL*")) /* Global-Brett -> Alle Nachrichten erreichbar */
  133.       result =
  134.       UMSSelectTags(MyUMSAccount, UMSTAG_SelWriteLocal, TRUE,
  135.                                 UMSTAG_SelSet,        KMSLSTATF_InGroup,
  136.                                 TAG_DONE);
  137.    else
  138.       result =
  139.       UMSSelectTags(MyUMSAccount, UMSTAG_WGroup,        mbname,
  140.                                 UMSTAG_SelWriteLocal, TRUE,
  141.                                 UMSTAG_SelSet,        KMSLSTATF_InGroup,
  142.                                 UMSTAG_SelQuick,      TRUE,
  143.                                 TAG_DONE);
  144.  
  145.    /* Für alle nicht sichtbaren Nachrichten Bit 2 wieder löschen */
  146.  
  147.    UMSMsgNum result2 =
  148.    UMSSelectTags(MyUMSAccount, UMSTAG_SelReadLocal,  TRUE,
  149.                              UMSTAG_SelMask,       KMSLSTATF_Visible|KMSLSTATF_InGroup,
  150.                              UMSTAG_SelMatch,      KMSLSTATF_InGroup,
  151.                              UMSTAG_SelWriteLocal, TRUE,
  152.                              UMSTAG_SelUnset,      KMSLSTATF_InGroup,
  153.                              TAG_DONE);
  154.  
  155.    return result-result2;
  156.    }
  157.  
  158. ///
  159.  
  160. /********************************
  161.  * Neue Areastruktur einrichten *
  162.  * TakeASem() von außen!        *
  163.  ********************************
  164.  * I: ---                       *
  165.  * O: struct AreaNode *         *
  166.  ********************************/
  167.  
  168. /// "InsertArea"
  169.  
  170. struct AreaNode *InsertArea(VOID)
  171.    {
  172.    struct AreaNode *apoint, *newapoint;
  173.    UWORD id = 0, previd = 0;
  174.  
  175.    apoint = (struct AreaNode *)KMSBase->AreaList.mlh_TailPred;
  176.    if (!apoint->Node.mln_Pred)
  177.       {
  178.       SystemError("InsertArea", "No AreaList!");
  179.       return NULL;
  180.       }
  181.  
  182.    /* Größte ID suchen */
  183.  
  184.    apoint = (struct AreaNode *)KMSBase->AreaList.mlh_Head;
  185.    while(apoint->Node.mln_Succ)
  186.       {
  187.       if (apoint->AreaData.ID > previd)
  188.          previd = apoint->AreaData.ID;
  189.  
  190.       apoint = apoint->Node.mln_Succ;
  191.       }
  192.  
  193.    if (previd + 1 == 0) /* ID-Überlauf */
  194.       {
  195.       previd = 0; id = 0;
  196.       apoint = (struct AreaNode *)KMSBase->AreaList.mlh_Head;
  197.       id = apoint->AreaData.ID;
  198.  
  199.       while(apoint->Node.mln_Succ && previd + 1 == id)
  200.          {
  201.          previd = id;
  202.  
  203.          apoint = (struct AreaNode *)apoint->Node.mln_Succ;
  204.          if (apoint->Node.mln_Succ)
  205.             id = apoint->AreaData.ID;
  206.          }
  207.       }
  208.  
  209.    if (previd == id)
  210.       {
  211.       SystemError("InsertArea", "Too many areas!");
  212.       return NULL;
  213.       }
  214.  
  215.    if (!(newapoint = (struct AreaNode *)AllocMem((ULONG)sizeof(struct AreaNode),MEMF_PUBLIC|MEMF_CLEAR)))
  216.       {
  217.       SystemError("InsertArea", "Out of memory!");
  218.       return NULL;
  219.       }
  220.    newapoint->AreaData.ID = previd + 1;
  221.  
  222.    Insert((struct List *)&KMSBase->AreaList, (struct Node *)newapoint, (struct Node *)apoint->Node.mln_Pred);
  223.  
  224.    return newapoint;
  225.    }
  226.  
  227. ///
  228.  
  229. /********************************
  230.  * Areastruktur löschen         *
  231.  * TakeASem() von außen         *
  232.  ********************************
  233.  * I: struct AreaNode *         *
  234.  * O: ---                       *
  235.  ********************************/
  236.  
  237. /// "DeleteArea"
  238.  
  239. VOID DeleteArea(struct AreaNode *target)
  240.    {
  241.    if (!target)
  242.       return;
  243.  
  244.    KMSBase->Modified |= MODIFIED_AREAS;
  245.  
  246.    Remove((struct Node *)target);
  247.  
  248.    FreeMem(target, (ULONG)sizeof(struct AreaNode));
  249.    }
  250.  
  251. ///
  252.  
  253. /********************************
  254.  * Area editieren/anlegen       *
  255.  ********************************
  256.  * I: Name, Flag (alt/neu)      *
  257.  * O: struct AreaNode *         *
  258.  * O: FALSE bei Fehler          *
  259.  ********************************/
  260.  
  261. /// "EditArea"
  262.  
  263. BOOL EditArea(STRPTR name, UWORD flag)
  264.    {
  265.    struct AreaNode *current;
  266.  
  267.    if (!(current = KMS_LC->Session.CurrentArea))
  268.       {
  269.       SystemError("EditArea", "No CurrentArea!");
  270.       return FALSE;
  271.       }
  272.  
  273.    Upper(name);
  274.  
  275.    if (name)
  276.       {
  277.       /* Angegebenes Brett edieren bzw. neu anlegen */
  278.  
  279.       if (strchr(name, '/') || strchr(name, '.'))
  280.          {
  281.          SysMsg(AREANAME_ONLY);
  282.          return FALSE;
  283.          }
  284.  
  285.       struct AreaNode *result = NULL;
  286.  
  287.       TakeASem(FALSE);
  288.       if (current->AreaData.Daughter)
  289.          {
  290.          result = SetArea(current->AreaData.Daughter);
  291.  
  292.          while(result && stricmp(result->AreaData.Name, name))
  293.             {
  294.             if (result->AreaData.Next)
  295.                result = SetArea(result->AreaData.Next);
  296.             else
  297.                result = NULL;
  298.             }
  299.          }
  300.       DropASem();
  301.  
  302.       if (result)
  303.          {
  304.          if (flag & AED_NEW)
  305.             {
  306.             SysMsg(AREA_ALREADY_EXISTS);
  307.             return FALSE;
  308.             }
  309.  
  310.          /* Edieren */
  311.  
  312.          SysMsg(EDIT_OLD_AREA);
  313.  
  314.          if (EditAreaInfo(result))
  315.             return TRUE;
  316.          else
  317.             return FALSE;
  318.          }
  319.       else
  320.          {
  321.          if (flag & AED_OLD)
  322.             {
  323.             SysMsg(AREA_NOT_FOUND);
  324.             return FALSE;
  325.             }
  326.  
  327.          /* Neu anlegen */
  328.  
  329.          TakeASem(TRUE);
  330.          if (result = InsertArea())
  331.             {
  332.             DropASem();
  333.  
  334.             SysMsg(EDIT_NEW_AREA);
  335.             strncpy(result->AreaData.Name, name, sizeof(result->AreaData.Name) - 1);
  336.             result->AreaData.Name[sizeof(result->AreaData.Name) - 1] = '\0';
  337.             result->AreaData.Type = ATYPE_NEWS;
  338.             result->AreaData.QuoteStr = 1;
  339.             result->AreaData.PQuoteStr = 1;
  340.             result->AreaData.ResendStr = 1;
  341.             result->AreaData.ForwardStr = 1;
  342.             result->AreaData.OriginStr = 1;
  343.  
  344.             if (!EditAreaInfo(result))
  345.                {
  346.                DeleteArea(result);
  347.                return FALSE;
  348.                }
  349.  
  350.             TakeASem(TRUE);
  351.  
  352.             if (!current->AreaData.Daughter)
  353.                {
  354.                /* Neue erste Tochter */
  355.  
  356.                current->AreaData.Daughter = result->AreaData.ID;
  357.                result->AreaData.Mother = current->AreaData.ID;
  358.                result->AreaData.Next = 0;
  359.                }
  360.             else
  361.                {
  362.                /* Weitere Tochter einsortieren */
  363.  
  364.                struct AreaNode *daughter = SetArea(current->AreaData.Daughter);
  365.                struct AreaNode *predaughter = NULL;
  366.  
  367.                while(daughter && stricmp(result->AreaData.Name,daughter->AreaData.Name) != -1)
  368.                   {
  369.                   predaughter = daughter;
  370.                   if (daughter->AreaData.Next)
  371.                      daughter = SetArea(daughter->AreaData.Next);
  372.                   else
  373.                      daughter = NULL;
  374.                   }
  375.  
  376.                result->AreaData.Mother = current->AreaData.ID;
  377.  
  378.                if (!predaughter)
  379.                   {
  380.                   /* Neue Area ist die erste */
  381.  
  382.                   result->AreaData.Next = daughter->AreaData.ID;
  383.                   current->AreaData.Daughter = result->AreaData.ID;
  384.                   }
  385.                else if (!daughter)
  386.                   {
  387.                   /* Neue Area ist die letzte */
  388.  
  389.                   predaughter->AreaData.Next = result->AreaData.ID;
  390.                   result->AreaData.Next = 0;
  391.                   }
  392.                else
  393.                   {
  394.                   /* Neue Area zwischen predaughter und daughter einhängen */
  395.  
  396.                   predaughter->AreaData.Next = result->AreaData.ID;
  397.                   result->AreaData.Next = daughter->AreaData.ID;
  398.                   }
  399.                }
  400.  
  401.             DropASem();
  402.             return TRUE;
  403.             }
  404.          else
  405.             {
  406.             DropASem();
  407.             SysMsg(EDIT_NEW_FAILED);
  408.             return FALSE;
  409.             }
  410.          }
  411.       }
  412.    else
  413.       {
  414.       /* Aktuelles Brett editieren */
  415.  
  416.       SysMsg(EDIT_OLD_AREA);
  417.  
  418.       if (EditAreaInfo(current))
  419.          {
  420.          KMS_LC->Session.CurrentAccess = CheckAccess(current);
  421.          return TRUE;
  422.          }
  423.       else
  424.          return FALSE;
  425.       }
  426.    }
  427.  
  428. ///
  429.  
  430. /********************************
  431.  * Area-Info editieren          *
  432.  ********************************
  433.  * I: struct AreaNode *         *
  434.  * O: FALSE: Plop/ShutDown      *
  435.  ********************************/
  436.  
  437. /// "EditAreaInfo"
  438.  
  439. BOOL EditAreaInfo(struct AreaNode *target)
  440.    {
  441.    LONG result;
  442.    struct Area area;
  443.  
  444.    KMSBase->Modified |= MODIFIED_AREAS;
  445.  
  446.    area = target->AreaData;
  447.  
  448.    CmdInput(NULL, PROMPT_ANAME, "/.", area.Name, sizeof(area.Name)-1, INF_PROMPT|INF_UPCASE|INF_NOEMPTY|INF_EXCLUDE|INF_DEFBUF);
  449.    if (Plop || ShutDown)
  450.       return FALSE;
  451.    strcpy(area.Name, KMS_LC->Session.InputBuffer);
  452.  
  453.    CmdInput(NULL, PROMPT_AINFO, NULL, area.Info, sizeof(area.Info)-1, INF_PROMPT|INF_DEFBUF);
  454.    if (Plop || ShutDown)
  455.       return FALSE;
  456.    strcpy(area.Info, KMS_LC->Session.InputBuffer);
  457.  
  458.    TEXT tmp[LEN_NUMBER+1];
  459.    TEXT def[2];
  460.  
  461.    if (area.ID != 1)
  462.       {
  463.       CmdInput(NULL, PROMPT_AMBNAME, NULL, area.MBName, sizeof(area.MBName)-1, INF_PROMPT|INF_NOEMPTY|INF_DEFBUF);
  464.       if (Plop || ShutDown)
  465.          return FALSE;
  466.       strcpy(area.MBName, KMS_LC->Session.InputBuffer);
  467.  
  468.       tmp[0] = KMSBase->AFlags[AFLAG_NEWS];
  469.       tmp[1] = KMSBase->AFlags[AFLAG_FILES];
  470.       tmp[2] = '\0';
  471.       if (area.Type & ATYPE_NEWS)
  472.          def[0] = KMSBase->AFlags[AFLAG_NEWS];
  473.       else if (area.Type & ATYPE_FILES)
  474.          def[0] = KMSBase->AFlags[AFLAG_FILES];
  475.       else
  476.          def[0] = '\0';
  477.       def[1] = '\0';
  478.       CmdInput(NULL, PROMPT_ATYPE, tmp, def, 1, INF_PROMPT|INF_UPCASE);
  479.       if (Plop || ShutDown)
  480.          return FALSE;
  481.      
  482.       area.Type &= ATYPE_GROUP;
  483.  
  484.       if (*KMS_LC->Session.InputBuffer == KMSBase->AFlags[AFLAG_NEWS])
  485.          area.Type |= ATYPE_NEWS;
  486.       else if (*KMS_LC->Session.InputBuffer == KMSBase->AFlags[AFLAG_FILES])
  487.          area.Type |= ATYPE_FILES;
  488.  
  489.       if (area.Type & ATYPE_GROUP)
  490.          strcpy(def, KMSBase->Yes);
  491.       else
  492.          strcpy(def, KMSBase->No);
  493.       CmdInput(NULL, PROMPT_USERGROUP, KMSBase->YNText, def, 1, INF_PROMPT|INF_UPCASE);
  494.       if (Plop || ShutDown)
  495.          return FALSE;
  496.       if (*KMS_LC->Session.InputBuffer == KMSBase->YNText[YES])
  497.          area.Type |= ATYPE_GROUP;
  498.       else
  499.          area.Type &= ~ATYPE_GROUP;
  500.       }
  501.    else
  502.       {
  503.       /* Root -> Private Post */
  504.  
  505.       *area.MBName = '\0'; /* Netmail -> Leerer Name */
  506.       area.Type = ATYPE_PRIVATE;
  507.       }
  508.  
  509.    if (area.Type & (ATYPE_FILES|ATYPE_PRIVATE))
  510.       {
  511.       BOOL ok = FALSE;
  512.       do
  513.          {
  514.          CmdInput(NULL, PROMPT_AFPATH, NULL, area.FilePath, sizeof(area.FilePath)-1, INF_PROMPT|INF_DEFBUF);
  515.          if (Plop || ShutDown)
  516.             return FALSE;
  517.          if (DirExists(KMS_LC->Session.InputBuffer))
  518.             {
  519.             strcpy(area.FilePath, KMS_LC->Session.InputBuffer);
  520.             ok = TRUE;
  521.             }
  522.          else
  523.             SysMsg(INVALID_DIR);
  524.          }
  525.          while(!ok);
  526.       }
  527.  
  528.    sprintf(tmp, "%d", area.ReadLevel);
  529.    result = CmdInput(NULL, PROMPT_AREAD, NULL, tmp, 3, INF_PROMPT|INF_NUMERIC);
  530.    if (Plop || ShutDown)
  531.       return FALSE;
  532.    area.ReadLevel = (UWORD)result;
  533.    sprintf(tmp, "%d", area.WriteLevel);
  534.    result = CmdInput(NULL, PROMPT_AWRITE, NULL, tmp, 3, INF_PROMPT|INF_NUMERIC);
  535.    if (Plop || ShutDown)
  536.       return FALSE;
  537.    area.WriteLevel = (UWORD)result;
  538.    sprintf(tmp, "%d", area.EditLevel);
  539.    result = CmdInput(NULL, PROMPT_AEDIT, NULL, tmp, 3, INF_PROMPT|INF_NUMERIC);
  540.    if (Plop || ShutDown)
  541.       return FALSE;
  542.    area.EditLevel = (UWORD)result;
  543.  
  544.    sprintf(tmp, "%d", area.HoldNum);
  545.    result = CmdInput(NULL, PROMPT_AHNUM, NULL, tmp, 4, INF_PROMPT|INF_NUMERIC);
  546.    if (Plop || ShutDown)
  547.       return FALSE;
  548.    area.HoldNum = (UWORD)result;
  549.  
  550.    sprintf(tmp, "%d", area.HoldDays);
  551.    result = CmdInput(NULL, PROMPT_AHDAYS, NULL, tmp, 4, INF_PROMPT|INF_NUMERIC);
  552.    if (Plop || ShutDown)
  553.       return FALSE;
  554.    area.HoldDays = (UWORD)result;
  555.  
  556.    area.AccessBits = SetAccessBits(area.AccessBits, PROMPT_ABITS);
  557.    if (Plop || ShutDown)
  558.       return FALSE;
  559.  
  560.    if (area.ID != 1)
  561.       {
  562.       if (area.WriteFlag & AWF_TONAME)
  563.          strcpy(def, KMSBase->Yes);
  564.       else
  565.          strcpy(def, KMSBase->No);
  566.       CmdInput(NULL, PROMPT_ATONAME, KMSBase->YNText, def, 1, INF_PROMPT|INF_UPCASE);
  567.       if (Plop || ShutDown)
  568.          return FALSE;
  569.       if (*KMS_LC->Session.InputBuffer == KMSBase->YNText[YES])
  570.          area.WriteFlag |= AWF_TONAME;
  571.       else
  572.          area.WriteFlag &= ~AWF_TONAME;
  573.       }
  574.  
  575.    if (area.WriteFlag & AWF_PSEUDO)
  576.       strcpy(def, KMSBase->Yes);
  577.    else
  578.       strcpy(def, KMSBase->No);
  579.    CmdInput(NULL, PROMPT_APSEUDO, KMSBase->YNText, def, 1, INF_PROMPT|INF_UPCASE);
  580.    if (Plop || ShutDown)
  581.       return FALSE;
  582.    if (*KMS_LC->Session.InputBuffer == KMSBase->YNText[YES])
  583.       area.WriteFlag |= AWF_PSEUDO;
  584.    else
  585.       area.WriteFlag &= ~AWF_PSEUDO;
  586.  
  587.    if (area.WriteFlag & AWF_NORE)
  588.       strcpy(def, KMSBase->No);
  589.    else
  590.       strcpy(def, KMSBase->Yes);
  591.    CmdInput(NULL, PROMPT_ARE, KMSBase->YNText, def, 1, INF_PROMPT|INF_UPCASE);
  592.    if (Plop || ShutDown)
  593.       return FALSE;
  594.    if (*KMS_LC->Session.InputBuffer == KMSBase->YNText[YES])
  595.       area.WriteFlag &= ~AWF_NORE;
  596.    else
  597.       area.WriteFlag |= AWF_NORE;
  598.  
  599.    sprintf(tmp, "%d", area.QuoteStr);
  600.    result = CmdInput(NULL, PROMPT_AQUOTES, NULL, tmp, 2, INF_PROMPT|INF_NUMERIC);
  601.    if (Plop || ShutDown)
  602.       return FALSE;
  603.    area.QuoteStr = (UWORD)result;
  604.    sprintf(tmp, "%d", area.PQuoteStr);
  605.    result = CmdInput(NULL, PROMPT_APQUOTES, NULL, tmp, 2, INF_PROMPT|INF_NUMERIC);
  606.    if (Plop || ShutDown)
  607.       return FALSE;
  608.    area.PQuoteStr = (UWORD)result;
  609.    sprintf(tmp, "%d", area.ResendStr);
  610.    result = CmdInput(NULL, PROMPT_ARESENDS, NULL, tmp, 2, INF_PROMPT|INF_NUMERIC);
  611.    if (Plop || ShutDown)
  612.       return FALSE;
  613.    area.ResendStr = (UWORD)result;
  614.    sprintf(tmp, "%d", area.ForwardStr);
  615.    result = CmdInput(NULL, PROMPT_AFORWS, NULL, tmp, 2, INF_PROMPT|INF_NUMERIC);
  616.    if (Plop || ShutDown)
  617.       return FALSE;
  618.    area.ForwardStr = (UWORD)result;
  619.    sprintf(tmp, "%d", area.OriginStr);
  620.    result = CmdInput(NULL, PROMPT_AORIGS, NULL, tmp, 2, INF_PROMPT|INF_NUMERIC);
  621.    if (Plop || ShutDown)
  622.       return FALSE;
  623.    area.OriginStr = (UWORD)result;
  624.  
  625.    Forbid();
  626.    target->AreaData = area;
  627.    Permit();
  628.  
  629.    return TRUE;
  630.    }
  631.  
  632. ///
  633.  
  634. /********************************
  635.  * Area entfernen/löschen       *
  636.  ********************************
  637.  * I: STRPTR name               *
  638.  * O: OK TRUE/FALSE             *
  639.  ********************************/
  640.  
  641. /// "RemoveArea"
  642.  
  643. BOOL RemoveArea(STRPTR name)
  644.    {
  645.    struct AreaNode *current;
  646.  
  647.    if (!(current = KMS_LC->Session.CurrentArea))
  648.       {
  649.       SystemError("RemoveArea", "No CurrentArea!");
  650.       return FALSE;
  651.       }
  652.  
  653.    if (!name)
  654.       {
  655.       /* Aktuelles Brett kann nicht gelöscht werden */
  656.  
  657.       SysMsg(AREA_NOT_DELETED);
  658.       return FALSE;
  659.       }
  660.    else
  661.       {
  662.       /* Angegebenes Brett löschen */
  663.  
  664.       if (strchr(name, '/') || strchr(name, '.'))
  665.          {
  666.          SysMsg(AREANAME_ONLY);
  667.          return FALSE;
  668.          }
  669.  
  670.       struct AreaNode *result = NULL;
  671.       struct AreaNode *preresult = NULL;
  672.  
  673.       TakeASem(FALSE);
  674.  
  675.       if (current->AreaData.Daughter)
  676.          {
  677.          result = SetArea(current->AreaData.Daughter);
  678.  
  679.          while(result && stricmp(result->AreaData.Name, name))
  680.             {
  681.             preresult = result;
  682.  
  683.             if (result->AreaData.Next)
  684.                result = SetArea(result->AreaData.Next);
  685.             else
  686.                result = NULL;
  687.             }
  688.          }
  689.  
  690.       if (!result)
  691.          {
  692.          /* Brett nicht vorhanden */
  693.  
  694.          DropASem();
  695.          SysMsg(AREA_NOT_FOUND);
  696.          return FALSE;
  697.          }
  698.       else
  699.          {
  700.          /* Wenn zu löschendes Brett Unterbretter besitzt, Schluss */
  701.  
  702.          if (result->AreaData.Daughter)
  703.             {
  704.             DropASem();
  705.             SysMsg(MOTHER_NOT_DELETED);
  706.             return FALSE;
  707.             }
  708.  
  709.          /* Wenn Area momentan CurrentArea eines Users, nicht löschen */
  710.  
  711.          TakeMSem(FALSE);
  712.          struct KMSNode *member = KMSBase->MemberList.mlh_Head;
  713.          while(member->Node.mln_Succ)
  714.             {
  715.             if (member->LCPtr->Session.CurrentArea == result)
  716.                {
  717.                DropMSem();
  718.                DropASem();
  719.                SysMsg(AREA_VISITOR);
  720.                return FALSE;
  721.                }
  722.             member = member->Node.mln_Succ;
  723.             }
  724.          DropMSem();
  725.  
  726.          DropASem();
  727.  
  728.          /* Nachrichten löschen? */
  729.  
  730.          UMSMsgNum num;
  731.  
  732.          if (num = SelectArea(result->AreaData.MBName))
  733.             {
  734.             TEXT buff[16];
  735.  
  736.             sprintf(buff, "%ld", num);
  737.             PPArg = buff;
  738.             SysMsg(MSGS_FOUND);
  739.             PPArg = NULL;
  740.  
  741.             if (YNRequest(DELETE_MSGS, FALSE))
  742.                {
  743.                num = UMSSelectTags(MyUMSAccount, UMSTAG_SelReadLocal,  TRUE,
  744.                                                UMSTAG_SelMask,       KMSLSTATF_InGroup|KMSLSTATF_Protected,
  745.                                                UMSTAG_SelMatch,      KMSLSTATF_InGroup|KMSLSTATF_Protected,
  746.                                                TAG_DONE);
  747.                if (num)
  748.                   {
  749.                   sprintf(buff, "%ld", num);
  750.                   PPArg = buff;
  751.                   SysMsg(PROT_MSGS_FOUND);
  752.                   PPArg = NULL;
  753.  
  754.                   if (YNRequest(DELETE_MSGS, FALSE))
  755.                      DeleteMsg(result, DEL_ALL);
  756.                   }
  757.                else
  758.                   DeleteMsg(result, DEL_ALL);
  759.                }
  760.             }
  761.  
  762.          SelectArea(KMS_LC->Session.CurrentArea->AreaData.MBName);
  763.  
  764.          /* Wirklich Gruppe löschen? */
  765.  
  766.          PPArg = name;
  767.          SysMsg(DELETING_AREA);
  768.          PPArg = NULL;
  769.          if (!YNRequest(REALLY_SURE, FALSE))
  770.             return FALSE;
  771.  
  772.          /* Wenn zu löschendes Brett erstes Tochterbrett ist, */
  773.          /* dann Mutter auf nächste Tochter einstimmen ;-)    */
  774.  
  775.          TakeASem(TRUE);
  776.  
  777.          if (result->AreaData.ID == current->AreaData.Daughter)
  778.             if (result->AreaData.Next)
  779.                current->AreaData.Daughter = result->AreaData.Next;
  780.             else
  781.                current->AreaData.Daughter = 0;
  782.  
  783.          /* Wenn zu löschendes Brett nicht einziges Unterbrett, */
  784.          /* dann "Next"-Zeiger aktualisieren                    */
  785.  
  786.          if (preresult)
  787.             preresult->AreaData.Next = result->AreaData.Next;
  788.  
  789.          /* Jetzt löschen */
  790.  
  791.          DeleteArea(result);
  792.  
  793.          DropASem();
  794.  
  795.          SysMsg(AREA_DELETED);
  796.  
  797.          return TRUE;
  798.          }
  799.       }
  800.    }
  801.  
  802. ///
  803.  
  804. /***************************************
  805.  * Brettliste                          *
  806.  ***************************************
  807.  * I: path: Pfadstring                 *
  808.  *    flag: ALIST_ALL, ALIST_NEXTNEW,  *
  809.  *          ALIST_WHOLE, ...           *
  810.  * O: TRUE: OK, FALSE: Userbreak       *
  811.  ***************************************/
  812.  
  813. /// "ListAreas"
  814.  
  815. BOOL ListAreas(STRPTR path, UWORD flag)
  816.    {
  817.    BOOL titel = TRUE;
  818.    BOOL stop = FALSE;
  819.    BOOL userbreak = FALSE;
  820.    struct AreaNode *current, *current0;
  821.    UBYTE curraccess;
  822.    UWORD busycount = 0;
  823.  
  824.    TakeASem(FALSE);
  825.  
  826.    if (path)
  827.       {
  828.       current = ChangeArea(path);
  829.       if (!current)
  830.          {
  831.          DropASem();
  832.          SysMsg(INVALID_PATH);
  833.          return FALSE;
  834.          }
  835.       }
  836.    else
  837.       {
  838.       current = KMS_LC->Session.CurrentArea;
  839.       if (!current)
  840.          {
  841.          DropASem();
  842.          SystemError("ListAreas", "No CurrentArea!");
  843.          return FALSE;
  844.          }
  845.       }
  846.  
  847.    if (!(flag & (ALIST_NEXTNEW|ALIST_NEXT|ALIST_NEXTSEL|ALIST_NEXTPROT)) && !current->AreaData.Daughter)
  848.       {
  849.       DropASem();
  850.       SysMsg(NO_AREAS_FOUND);
  851.       return FALSE;
  852.       }
  853.  
  854.    current0 = current;
  855.  
  856.    while(!userbreak && current)
  857.       {
  858.       /* Busy-Counter erhöhen, evt. Lebenszeichen geben */
  859.  
  860.       if (titel && busycount++ == 10)
  861.          SysMsg(SEARCHING);
  862.       else if (titel && busycount > 10 && busycount % 2)
  863.          Print(".", PF_NOLF|PF_NOBRK);
  864.  
  865.       /* Nächste Area */
  866.  
  867.       if (current->AreaData.Daughter && !stop)
  868.          {
  869.          current = SetArea(current->AreaData.Daughter);
  870.          if (!(flag & ALIST_WHOLE))
  871.             stop = TRUE;
  872.          }
  873.       else if (current->AreaData.Next)
  874.          {
  875.          current = SetArea(current->AreaData.Next);
  876.          if (!(flag & ALIST_WHOLE))
  877.             stop = TRUE;
  878.          else
  879.             stop = FALSE;
  880.          }
  881.       else if (flag & ALIST_WHOLE)
  882.          {
  883.          if (current->AreaData.Mother)
  884.             current = SetArea(current->AreaData.Mother);
  885.          else
  886.             current = NULL;
  887.          stop = TRUE;
  888.          }
  889.       else
  890.          current = NULL;
  891.  
  892.       if (current && !(flag & (ALIST_NEXTNEW|ALIST_NEXT|ALIST_NEXTSEL|ALIST_NEXTPROT)) && current->AreaData.Mother == current0->AreaData.Mother)
  893.          current = NULL;
  894.  
  895.       /* Areadaten ausgeben */
  896.  
  897.       if (current && (!stop || !(flag & ALIST_WHOLE)) && (curraccess = CheckAccess(current)))
  898.          {
  899.          SelectArea(current->AreaData.MBName);
  900.  
  901.          /* Wenn passende Gruppe gefunden */
  902.  
  903.          if (flag & (ALIST_ALL|ALIST_NEXT) || (flag & (ALIST_NEXTNEW|ALIST_NEW) && NextMsg(0, MLIST_NEW))
  904.                                           || (flag & (ALIST_NEXTSEL|ALIST_SEL) && NextMsg(0, MLIST_SEL))
  905.                                           || (flag & (ALIST_NEXTPROT|ALIST_PROT) && NextMsg(0, MLIST_PROT)))
  906.             {
  907.             if (titel)
  908.                {
  909.                if (!(flag & ALIST_QUIET))
  910.                   {
  911.                   if (flag & ALIST_ALL)
  912.                      {
  913.                      CreatePath(current0);
  914.                      PPArg = PathString;
  915.                      SysMsg(DIRLST_ALL);
  916.                      PPArg = NULL;
  917.                      }
  918.                   else if (flag & ALIST_NEXT)
  919.                      SysMsg(DIRLST_NEXT);
  920.                   else if (flag & ALIST_NEW)
  921.                      SysMsg(DIRLST_NEW);
  922.                   else if (flag & ALIST_NEXTNEW)
  923.                      SysMsg(DIRLST_NEXTNEW);
  924.                   else if (flag & ALIST_SEL)
  925.                      SysMsg(DIRLST_SEL);
  926.                   else if (flag & ALIST_NEXTSEL)
  927.                      SysMsg(DIRLST_NEXTSEL);
  928.                   else if (flag & ALIST_PROT)
  929.                      SysMsg(DIRLST_PROT);
  930.                   else if (flag & ALIST_NEXTPROT)
  931.                      SysMsg(DIRLST_NEXTPROT);
  932.  
  933.                   SysMsg(DIRLST_HEAD);
  934.  
  935.                   KMS_LC->Session.LineCounter = 6;
  936.                   }
  937.                else if (busycount >= 10)
  938.                   Print(NULL, 0);
  939.  
  940.                titel = FALSE;
  941.                }
  942.  
  943.             userbreak = PrintAreaInfo(current, curraccess);
  944.  
  945.             /* Wechsel in nächstes Brett? */
  946.  
  947.             if (flag & (ALIST_NEXTNEW|ALIST_NEXT|ALIST_NEXTSEL|ALIST_NEXTPROT))
  948.                {
  949.                KMS_LC->Session.CurrentArea = current;
  950.                KMS_LC->Session.CurrentAccess = curraccess;
  951.  
  952.                if (KMS_LC->Session.CurrentUser->UserData.Flags & UF_AUTO_LIST)
  953.                   {
  954.                   Print(NULL, 0);
  955.  
  956.                   if (flag & ALIST_NEXTNEW)
  957.                      userbreak = ListMsgs(current, MLIST_NEW);
  958.                   else if (flag & ALIST_NEXTSEL)
  959.                      userbreak = ListMsgs(current, MLIST_SEL);
  960.                   else if (flag & ALIST_NEXTPROT)
  961.                      userbreak = ListMsgs(current, MLIST_PROT);
  962.                   }
  963.  
  964.                current = NULL;
  965.                }
  966.             }
  967.          }
  968.       }
  969.  
  970.    DropASem();
  971.  
  972.    if (busycount >= 10 && titel)
  973.       Print(NULL, 0);
  974.  
  975.    if (titel)
  976.       {
  977.       if (flag & ALIST_NEXTNEW)
  978.          SysMsg(NO_NEXTNEW_AREA);
  979.       else if (flag & ALIST_NEXTSEL)
  980.          SysMsg(NO_NEXTSEL_AREA);
  981.       else if (flag & ALIST_NEXTPROT)
  982.          SysMsg(NO_NEXTPROT_AREA);
  983.       else if (flag & ALIST_NEXT)
  984.          SysMsg(NO_NEXT_AREA);
  985.       else
  986.          SysMsg(NO_AREAS_FOUND);
  987.  
  988.       userbreak = TRUE;
  989.       }
  990.  
  991.    return !userbreak;
  992.    }
  993.  
  994. ///
  995.  
  996. /***************************************
  997.  *  Eine Zeile der Arealiste ausgeben  *
  998.  ***************************************
  999.  * I: struct AreaNode *                *
  1000.  * O: Abbruch durch CTRL-C/X: TRUE     *
  1001.  ***************************************/
  1002.  
  1003. /// "PrintAreaInfo"
  1004.  
  1005. BOOL PrintAreaInfo(struct AreaNode *area, UBYTE curracc)
  1006.    {
  1007.    UBYTE result, type;
  1008.    TEXT merk[LEN_KMSPATH+16], line[LEN_KMSPATH+16];
  1009.  
  1010.    if (!area)
  1011.       return FALSE;
  1012.  
  1013.    /* Area-Typ und Zugriffs-Flags */
  1014.  
  1015.    strcpy(merk, " - --- ");
  1016.  
  1017.    type = area->AreaData.Type;
  1018.    if (type & ATYPE_PRIVATE)
  1019.       merk[1] = KMSBase->AFlags[AFLAG_PRIVATE]; /* 'P'rivate Post */
  1020.    else if (type & ATYPE_FILES)
  1021.       merk[1] = KMSBase->AFlags[AFLAG_FILES]; /* 'F'iles */
  1022.    else if (type & ATYPE_NEWS)
  1023.       merk[1] = KMSBase->AFlags[AFLAG_NEWS]; /* 'N'achrichten */
  1024.  
  1025.    if (type & ATYPE_GROUP)
  1026.       merk[2] = '!'; /* 'G'ruppenbrett */
  1027.  
  1028.    if (curracc & AACC_READ)
  1029.       merk[3] = KMSBase->AFlags[AFLAG_READ]; /* 'R'ead */
  1030.    if (curracc & AACC_WRITE)
  1031.       merk[4] = KMSBase->AFlags[AFLAG_WRITE]; /* 'W'rite */
  1032.    if (curracc & AACC_EDIT)
  1033.       merk[5] = KMSBase->AFlags[AFLAG_EDIT]; /* 'E'dit */
  1034.  
  1035.    strcpy(line, merk);
  1036.  
  1037.    /* Pfad-String konstruieren */
  1038.  
  1039.    CreatePath(area);
  1040.  
  1041.    strcat(line, PathString);
  1042.    line[KMS_LC->Session.CurrentUser->UserData.LineLen] = '\0';
  1043.    strcat(line, "\n");
  1044.  
  1045.    /* Zeile ausgeben */
  1046.  
  1047.    PPArg = line;
  1048.    result = MsgParsePrint(KMSBase->AreaListPath, MP_NOWRAP);
  1049.    PPArg = NULL;
  1050.    if (!result)
  1051.       {
  1052.       TEXT info[LEN_AREAINFO+16];
  1053.  
  1054.       sprintf(info, "       %s\n",area->AreaData.Info);
  1055.  
  1056.       PPArg = info;
  1057.       result = MsgParsePrint(KMSBase->AreaListInfo, MP_NOWRAP);
  1058.       PPArg = NULL;
  1059.       }
  1060.  
  1061.    return (BOOL)result;
  1062.    }
  1063.  
  1064. ///
  1065.  
  1066. /***************************************
  1067.  * Aktuelles Brett wechseln            *
  1068.  ***************************************
  1069.  * I: STPRTR pfadangabe                *
  1070.  * O: Erfolg TRUE/FALSE                *
  1071.  ***************************************/
  1072.  
  1073. /// "ChangePath"
  1074.  
  1075. BOOL ChangePath(STRPTR path)
  1076.    {
  1077.    UMSMsgNum num;
  1078.    TEXT all[LEN_NUMBER+1];
  1079.    TEXT new[LEN_NUMBER+1];
  1080.  
  1081.    struct AreaNode *apoint = ChangeArea(path);
  1082.    if (apoint)
  1083.       {
  1084.       SelectArea(apoint->AreaData.MBName);
  1085.  
  1086.       KMS_LC->Session.CurrentArea = apoint;
  1087.       KMS_LC->Session.CurrentAccess = CheckAccess(apoint);
  1088.  
  1089.       ReadMsg(0, RF_RESET);
  1090.  
  1091.       num = UMSSelectTags(MyUMSAccount, UMSTAG_SelReadLocal, TRUE,
  1092.                                       UMSTAG_SelMask,      KMSLSTATF_InGroup,
  1093.                                       UMSTAG_SelMatch,     KMSLSTATF_InGroup,
  1094.                                       TAG_DONE);
  1095.       sprintf(all, "%ld", num);
  1096.       PPArg = all;
  1097.       num = UMSSelectTags(MyUMSAccount, UMSTAG_SelReadLocal, TRUE,
  1098.                                       UMSTAG_SelMask,      KMSLSTATF_Unread|KMSLSTATF_InGroup,
  1099.                                       UMSTAG_SelMatch,     KMSLSTATF_Unread|KMSLSTATF_InGroup,
  1100.                                       TAG_DONE);
  1101.       sprintf(new, "%ld", num);
  1102.       PPArg2 = new;
  1103.       SysMsg(DIRLST_ACT);
  1104.       PPArg2 = NULL;
  1105.       PPArg = NULL;
  1106.  
  1107.       SysMsg(DIRLST_HEAD);
  1108.  
  1109.       PrintAreaInfo(apoint, KMS_LC->Session.CurrentAccess);
  1110.  
  1111.       if (KMS_LC->Session.CurrentUser->UserData.Flags & UF_AUTO_AREALIST)
  1112.          {
  1113.          Print(NULL, 0);
  1114.          ListAreas(NULL, ALIST_ALL);
  1115.          }
  1116.  
  1117.       return TRUE;
  1118.       }
  1119.    else
  1120.       return FALSE;
  1121.    }
  1122.  
  1123. ///
  1124.  
  1125. /***************************************
  1126.  *  Pfad-String konstruieren           *
  1127.  ***************************************
  1128.  * I: struct AreaNode *                *
  1129.  * O: ---                              *
  1130.  ***************************************/
  1131.  
  1132. /// "CreatePath"
  1133.  
  1134. VOID CreatePath(struct AreaNode *area)
  1135.    {
  1136.    struct AreaNode *apoint;
  1137.    TEXT merk[LEN_KMSPATH+1];
  1138.  
  1139.    if (!area)
  1140.       {
  1141.       *PathString = '\0';
  1142.       return;
  1143.       }
  1144.  
  1145.    /* Pfad-String konstruieren */
  1146.  
  1147.    strcpy(PathString, area->AreaData.Name);
  1148.  
  1149.    TakeASem(FALSE);
  1150.  
  1151.    apoint = area;
  1152.    while(apoint && apoint->AreaData.Mother && strlen(PathString) < LEN_KMSPATH)
  1153.       {
  1154.       apoint = SetArea(apoint->AreaData.Mother);
  1155.       strcpy(merk, PathString);
  1156.       if (apoint && apoint->AreaData.Mother)
  1157.          strcpy(PathString, apoint->AreaData.Name);
  1158.       else
  1159.          strcpy(PathString, "");
  1160.       strcat(PathString, "/");
  1161.       strncat(PathString, merk, LEN_KMSPATH - strlen(merk));
  1162.       PathString[LEN_KMSPATH] = '\0';
  1163.       }
  1164.  
  1165.    DropASem();
  1166.    }
  1167.  
  1168. ///
  1169.  
  1170. /*********************************
  1171.  * Area wechseln                 *
  1172.  *********************************
  1173.  * I: Pfad                       *
  1174.  * O: Neue Area                  *
  1175.  *********************************/
  1176.  
  1177. /// "ChangeArea"
  1178.  
  1179. struct AreaNode *ChangeArea(STRPTR path)
  1180.    {
  1181.    struct AreaNode *current;
  1182.    BOOL pathsearch = FALSE;
  1183.    BOOL begin = TRUE;
  1184.    TEXT token[LEN_AREANAME+1];
  1185.  
  1186.    if (!path || !strlen(path))
  1187.       return NULL;
  1188.  
  1189.    if (!(current = KMS_LC->Session.CurrentArea))
  1190.       {
  1191.       SystemError("ChangeArea", "No CurrentArea!");
  1192.       return NULL;
  1193.       }
  1194.  
  1195.    if (strchr(path, '/') || strchr(path, '.'))
  1196.       {
  1197.       /* Angegebenen Pfad streng verfolgen */
  1198.       /* BRETT MAUS/AMIGA */
  1199.       /* BRETT /MAUS/AMIGA */
  1200.       /* BRETT / */
  1201.       /* BRETT . */
  1202.  
  1203.       TakeASem(FALSE);
  1204.  
  1205.       do
  1206.          {
  1207.          path = PathParse(path, token);
  1208.  
  1209.          if (!strcmp(token, "/") && begin)
  1210.             {
  1211.             /* Wechsel ins Hauptverzeichnis (Private Mail) */
  1212.  
  1213.             current = SetArea(1);
  1214.             }
  1215.  
  1216.          if (strcmp(token, ".") && begin && *path) /* Wenn nicht "." allein angegeben war */
  1217.             {
  1218.             /* Wechsel ins Unterverzeichnis */
  1219.  
  1220.             current = SetArea(current->AreaData.Daughter);
  1221.             }
  1222.  
  1223.          if (!strcmp(token, "/"))
  1224.             {
  1225.             /* Wechsel ins Unterverzeichnis */
  1226.  
  1227.             if (!begin)
  1228.                current = SetArea(current->AreaData.Daughter);
  1229.             }
  1230.          else if (!strcmp(token, "."))
  1231.             {
  1232.             /* Einen Zweig höher gehen */
  1233.  
  1234.             current = SetArea(current->AreaData.Mother);
  1235.             }
  1236.          else
  1237.             {
  1238.             /* Brettname im aktuellen Verzeichnis suchen */
  1239.  
  1240.             while(current && stricmp(current->AreaData.Name, token))
  1241.                current = SetArea(current->AreaData.Next);
  1242.             }
  1243.  
  1244.          begin = FALSE;
  1245.  
  1246.          } while(*path && current);
  1247.  
  1248.       DropASem();
  1249.  
  1250.       if (CheckAccess(current))
  1251.          return current;
  1252.       else
  1253.          return NULL;
  1254.       }
  1255.    else
  1256.       {
  1257.       /* Einzelnes Brett global suchen: Ab aktuellem und dann, falls
  1258.          nicht gefunden, von vorne */
  1259.  
  1260.       current = SeekAreaName(current, path);
  1261.       if (!current)
  1262.          {
  1263.          current = SetArea(1);
  1264.          current = SeekAreaName(current, path);
  1265.          }
  1266.  
  1267.       if (CheckAccess(current))
  1268.          return current;
  1269.       else
  1270.          return NULL;
  1271.       }
  1272.    }
  1273.  
  1274. ///
  1275.  
  1276. /*********************************************
  1277.  * Nächsten Brettnamen aus Pfadangabe ziehen *
  1278.  *********************************************
  1279.  * I: Pfadstring, Tokenbuffer                *
  1280.  * O: Modifizierter Pfadstring               *
  1281.  *********************************************/
  1282.  
  1283. /// "PathParse"
  1284.  
  1285. STRPTR PathParse(STRPTR string, STRPTR tok)
  1286.    {
  1287.    UWORD n = 0;
  1288.  
  1289.    *tok = '\0';
  1290.  
  1291.    if (*string == '/' || *string == '.')
  1292.       {
  1293.       tok[0] = *string;
  1294.       tok[1] = '\0';
  1295.       return ++string;
  1296.       }
  1297.  
  1298.    while(*string && *string != '/' && *string != '.')
  1299.       {
  1300.       tok[n++] = *string;
  1301.       string++;
  1302.       }
  1303.  
  1304.    tok[n] = '\0';
  1305.  
  1306.    return string;
  1307.    }
  1308.  
  1309. ///
  1310.  
  1311. /*******************************************
  1312.  * Area mit bestimmtem Namen global suchen *
  1313.  *******************************************
  1314.  * I: Start-Area, Name                     *
  1315.  * O: Gefundene Area oder NULL             *
  1316.  *******************************************/
  1317.  
  1318. /// "SeekAreaName"
  1319.  
  1320. struct AreaNode *SeekAreaName(struct AreaNode *current, STRPTR name)
  1321.    {
  1322.    BOOL goon = TRUE;
  1323.    BOOL stop = FALSE;
  1324.    TEXT buf[LEN_AREANAME+1];
  1325.    UWORD len;
  1326.  
  1327.    TakeASem(FALSE);
  1328.  
  1329.    while(current && goon)
  1330.       {
  1331.       if (current->AreaData.Daughter && !stop)
  1332.          {
  1333.          current = SetArea(current->AreaData.Daughter);
  1334.          stop = FALSE;
  1335.          }
  1336.       else if (current->AreaData.Next)
  1337.          {
  1338.          current = SetArea(current->AreaData.Next);
  1339.          stop = FALSE;
  1340.          }
  1341.       else
  1342.          {
  1343.          current = SetArea(current->AreaData.Mother);
  1344.          stop = TRUE;
  1345.          }
  1346.  
  1347.       len = strlen(name);
  1348.       if (len > LEN_AREANAME)
  1349.          len = LEN_AREANAME;
  1350.       strncpy(buf, current->AreaData.Name, len);
  1351.       buf[len] = '\0';
  1352.  
  1353.       if (current && (!stop || !current->AreaData.Mother) && !stricmp(buf, name))
  1354.          goon = FALSE;
  1355.       }
  1356.  
  1357.    DropASem();
  1358.  
  1359.    return current;
  1360.    }
  1361.  
  1362. ///
  1363.  
  1364. /*******************************************
  1365.  * UMS-MsgBase-Namen global suchen         *
  1366.  *******************************************
  1367.  * I: gesuchte Area                        *
  1368.  * O: AreaNode                             *
  1369.  *******************************************/
  1370.  
  1371. /// "AreaSearch"
  1372.  
  1373. struct AreaNode *AreaSearch(STRPTR name)
  1374.    {
  1375.    struct AreaNode *apoint;
  1376.  
  1377.    TakeASem(FALSE);
  1378.  
  1379.    apoint = (struct AreaNode *)KMSBase->AreaList.mlh_Head;
  1380.    while(apoint->Node.mln_Succ)
  1381.       {
  1382.       if (!stricmp(name, apoint->AreaData.MBName))
  1383.          {
  1384.          DropASem();
  1385.          return apoint;
  1386.          }
  1387.  
  1388.       apoint = apoint->Node.mln_Succ;
  1389.       }
  1390.  
  1391.    DropASem();
  1392.  
  1393.    return NULL;
  1394.    }
  1395.  
  1396. ///
  1397.  
  1398. /*********************************
  1399.  * Aenderungen in mehreren Areas *
  1400.  *********************************
  1401.  * I: Pfad, Flag                 *
  1402.  * O: Erfolg TRUE/FALSE          *
  1403.  *********************************/
  1404.  
  1405. /// "AreaModify"
  1406.  
  1407. BOOL AreaModify(STRPTR path, UWORD flag)
  1408.    {
  1409.    LONG result;
  1410.    ULONG bits;
  1411.  
  1412.    if (path && !ChangeArea(path))
  1413.       {
  1414.       SysMsg(INVALID_PATH);
  1415.       return FALSE;
  1416.       }
  1417.  
  1418.    result = CmdInput(NULL, PROMPT_AREAD, NULL, "", 3, INF_PROMPT|INF_NUMERIC);
  1419.    if (Plop || ShutDown)
  1420.       return FALSE;
  1421.    if (strlen(KMS_LC->Session.InputBuffer))
  1422.       return GlobalAreaChange(path, flag, GAC_RLEVEL, result);
  1423.    result = CmdInput(NULL, PROMPT_AWRITE, NULL, "", 3, INF_PROMPT|INF_NUMERIC);
  1424.    if (Plop || ShutDown)
  1425.       return FALSE;
  1426.    if (strlen(KMS_LC->Session.InputBuffer))
  1427.       return GlobalAreaChange(path, flag, GAC_WLEVEL, result);
  1428.    result = CmdInput(NULL, PROMPT_AEDIT, NULL, "", 3, INF_PROMPT|INF_NUMERIC);
  1429.    if (Plop || ShutDown)
  1430.       return FALSE;
  1431.    if (strlen(KMS_LC->Session.InputBuffer))
  1432.       return GlobalAreaChange(path, flag, GAC_ELEVEL, result);
  1433.  
  1434.    result = CmdInput(NULL, PROMPT_AHNUM, NULL, "", 4, INF_PROMPT|INF_NUMERIC);
  1435.    if (Plop || ShutDown)
  1436.       return FALSE;
  1437.    if (strlen(KMS_LC->Session.InputBuffer))
  1438.       return GlobalAreaChange(path, flag, GAC_HNUM, result);
  1439.  
  1440.    result = CmdInput(NULL, PROMPT_AHDAYS, NULL, "", 4, INF_PROMPT|INF_NUMERIC);
  1441.    if (Plop || ShutDown)
  1442.       return FALSE;
  1443.    if (strlen(KMS_LC->Session.InputBuffer))
  1444.       return GlobalAreaChange(path, flag, GAC_HDAYS, result);
  1445.  
  1446.    bits = SetAccessBits(0, PROMPT_AADDBITS);
  1447.    if (Plop || ShutDown)
  1448.       return FALSE;
  1449.    if (bits)
  1450.       return GlobalAreaChange(path, flag, GAC_ADDBITS, bits);
  1451.  
  1452.    bits = SetAccessBits(0, PROMPT_ADELBITS);
  1453.    if (Plop || ShutDown)
  1454.       return FALSE;
  1455.    if (bits)
  1456.       return GlobalAreaChange(path, flag, GAC_DELBITS, bits);
  1457.  
  1458.    CmdInput(NULL, PROMPT_ATONAME, KMSBase->YNText, "", 1, INF_PROMPT|INF_UPCASE);
  1459.    if (Plop || ShutDown)
  1460.       return FALSE;
  1461.    if (*KMS_LC->Session.InputBuffer == KMSBase->YNText[YES])
  1462.       return GlobalAreaChange(path, flag, GAC_WFTONAME, 1);
  1463.    else if (* KMS_LC->Session.InputBuffer == KMSBase->YNText[NO])
  1464.       return GlobalAreaChange(path, flag, GAC_WFTONAME, 0);
  1465.  
  1466.    CmdInput(NULL, PROMPT_APSEUDO, KMSBase->YNText, "", 1, INF_PROMPT|INF_UPCASE);
  1467.    if (Plop || ShutDown)
  1468.       return FALSE;
  1469.    if (*KMS_LC->Session.InputBuffer == KMSBase->YNText[YES])
  1470.       return GlobalAreaChange(path, flag, GAC_WFPSEUDO, 1);
  1471.    else if (* KMS_LC->Session.InputBuffer == KMSBase->YNText[NO])
  1472.       return GlobalAreaChange(path, flag, GAC_WFPSEUDO, 0);
  1473.  
  1474.    CmdInput(NULL, PROMPT_ARE, KMSBase->YNText, "", 1, INF_PROMPT|INF_UPCASE);
  1475.    if (Plop || ShutDown)
  1476.       return FALSE;
  1477.    if (*KMS_LC->Session.InputBuffer == KMSBase->YNText[YES])
  1478.       return GlobalAreaChange(path, flag, GAC_WFNORE, 1);
  1479.    else if (* KMS_LC->Session.InputBuffer == KMSBase->YNText[NO])
  1480.       return GlobalAreaChange(path, flag, GAC_WFNORE, 0);
  1481.  
  1482.    result = CmdInput(NULL, PROMPT_AQUOTES, NULL, "", 2, INF_PROMPT|INF_NUMERIC);
  1483.    if (Plop || ShutDown)
  1484.       return FALSE;
  1485.    if (strlen(KMS_LC->Session.InputBuffer))
  1486.       return GlobalAreaChange(path, flag, GAC_QUOTES, result);
  1487.    result = CmdInput(NULL, PROMPT_APQUOTES, NULL, "", 2, INF_PROMPT|INF_NUMERIC);
  1488.    if (Plop || ShutDown)
  1489.       return FALSE;
  1490.    if (strlen(KMS_LC->Session.InputBuffer))
  1491.       return GlobalAreaChange(path, flag, GAC_PQUOTES, result);
  1492.    result = CmdInput(NULL, PROMPT_ARESENDS, NULL, "", 2, INF_PROMPT|INF_NUMERIC);
  1493.    if (Plop || ShutDown)
  1494.       return FALSE;
  1495.    if (strlen(KMS_LC->Session.InputBuffer))
  1496.       return GlobalAreaChange(path, flag, GAC_RESENDS, result);
  1497.    result = CmdInput(NULL, PROMPT_AFORWS, NULL, "", 2, INF_PROMPT|INF_NUMERIC);
  1498.    if (Plop || ShutDown)
  1499.       return FALSE;
  1500.    if (strlen(KMS_LC->Session.InputBuffer))
  1501.       return GlobalAreaChange(path, flag, GAC_FORWS, result);
  1502.    result = CmdInput(NULL, PROMPT_AORIGS, NULL, "", 2, INF_PROMPT|INF_NUMERIC);
  1503.    if (Plop || ShutDown)
  1504.       return FALSE;
  1505.    if (strlen(KMS_LC->Session.InputBuffer))
  1506.       return GlobalAreaChange(path, flag, GAC_ORIGS, result);
  1507.  
  1508.    return TRUE;
  1509.    }
  1510.  
  1511. ///
  1512.  
  1513. /*********************************
  1514.  * Aenderungen in mehreren Areas *
  1515.  *********************************
  1516.  * I: Pfad, Flag, Code, Wert     *
  1517.  * O: Erfolg TRUE/FALSE          *
  1518.  *********************************/
  1519.  
  1520. /// "GlobalAreaChange"
  1521.  
  1522. BOOL GlobalAreaChange(STRPTR path, UWORD flag, UWORD code, ULONG value)
  1523.    {
  1524.    BOOL titel = TRUE;
  1525.    BOOL stop = FALSE;
  1526.  
  1527.    TakeASem(FALSE);
  1528.  
  1529.    struct AreaNode *current, *current0;
  1530.  
  1531.    if (path)
  1532.       {
  1533.       current = ChangeArea(path);
  1534.       if (!current)
  1535.          {
  1536.          DropASem();
  1537.          SysMsg(INVALID_PATH);
  1538.          return FALSE;
  1539.          }
  1540.       }
  1541.    else
  1542.       {
  1543.       current = KMS_LC->Session.CurrentArea;
  1544.       if (!current)
  1545.          {
  1546.          DropASem();
  1547.          SystemError("ListAreas", "No CurrentArea!");
  1548.          return FALSE ;
  1549.          }
  1550.       }
  1551.  
  1552.    if (!current->AreaData.Daughter)
  1553.       {
  1554.       DropASem();
  1555.       SysMsg(NO_AREAS_FOUND);
  1556.       return FALSE;
  1557.       }
  1558.  
  1559.    KMSBase->Modified |= MODIFIED_AREAS;
  1560.  
  1561.    current0 = current;
  1562.  
  1563.    while(current)
  1564.       {
  1565.       /* Nächste Area */
  1566.  
  1567.       if (current->AreaData.Daughter && !stop)
  1568.          {
  1569.          current = SetArea(current->AreaData.Daughter);
  1570.          if (!(flag & ALIST_WHOLE))
  1571.             stop = TRUE;
  1572.          }
  1573.       else if (current->AreaData.Next)
  1574.          {
  1575.          current = SetArea(current->AreaData.Next);
  1576.          if (!(flag & ALIST_WHOLE))
  1577.             stop = TRUE;
  1578.          else
  1579.             stop = FALSE;
  1580.          }
  1581.       else if (flag & ALIST_WHOLE)
  1582.          {
  1583.          if (current->AreaData.Mother)
  1584.             current = SetArea(current->AreaData.Mother);
  1585.          else
  1586.             current = NULL;
  1587.          stop = TRUE;
  1588.          }
  1589.       else
  1590.          current = NULL;
  1591.  
  1592.       if (current && current->AreaData.Mother == current0->AreaData.Mother)
  1593.          current = NULL;
  1594.  
  1595.       /* Areadaten ausgeben */
  1596.  
  1597.       if (current && (!stop || !(flag & ALIST_WHOLE)))
  1598.          {
  1599.          /* Wenn passende Gruppe gefunden */
  1600.  
  1601.          SelectArea(current->AreaData.MBName);
  1602.  
  1603.          if (titel)
  1604.             {
  1605.             SysMsg(DIRLST_MOD);
  1606.             SysMsg(DIRLST_HEAD);
  1607.  
  1608.             KMS_LC->Session.LineCounter = 6;
  1609.  
  1610.             titel = FALSE;
  1611.             }
  1612.  
  1613.          PrintAreaInfo(current, CheckAccess(current));
  1614.  
  1615.          if (code & (GAC_RLEVEL|GAC_WLEVEL|GAC_ELEVEL))
  1616.             if (value > 255)
  1617.                value = 255;
  1618.          if (code & GAC_RLEVEL)
  1619.             current->AreaData.ReadLevel = (UBYTE)value;
  1620.          if (code & GAC_WLEVEL)
  1621.             current->AreaData.WriteLevel = (UBYTE)value;
  1622.          if (code & GAC_ELEVEL)
  1623.             current->AreaData.EditLevel = (UBYTE)value;
  1624.          else if (code & GAC_HNUM)
  1625.             current->AreaData.HoldNum = (UBYTE)value;
  1626.          else if (code & GAC_HDAYS)
  1627.             current->AreaData.HoldDays = (UBYTE)value;
  1628.          else if (code & GAC_DELBITS)
  1629.             current->AreaData.AccessBits &= ~value;
  1630.          else if (code & GAC_ADDBITS)
  1631.             current->AreaData.AccessBits |= value;
  1632.          else if (code & GAC_WFTONAME)
  1633.             {
  1634.             if (value == 1)
  1635.                current->AreaData.WriteFlag |= AWF_TONAME;
  1636.             else
  1637.                current->AreaData.WriteFlag &= ~AWF_TONAME;
  1638.             }
  1639.          else if (code & GAC_WFPSEUDO)
  1640.             {
  1641.             if (value == 1)
  1642.                current->AreaData.WriteFlag |= AWF_PSEUDO;
  1643.             else
  1644.                current->AreaData.WriteFlag &= ~AWF_PSEUDO;
  1645.             }
  1646.          else if (code & GAC_WFNORE)
  1647.             {
  1648.             if (value == 1)
  1649.                current->AreaData.WriteFlag &= ~AWF_NORE;
  1650.             else
  1651.                current->AreaData.WriteFlag |= AWF_NORE;
  1652.             }
  1653.          else if (code & GAC_QUOTES)
  1654.             current->AreaData.QuoteStr = (UBYTE)value;
  1655.          else if (code & GAC_PQUOTES)
  1656.             current->AreaData.PQuoteStr = (UBYTE)value;
  1657.          else if (code & GAC_RESENDS)
  1658.             current->AreaData.ResendStr = (UBYTE)value;
  1659.          else if (code & GAC_FORWS)
  1660.             current->AreaData.ForwardStr = (UBYTE)value;
  1661.          else if (code & GAC_ORIGS)
  1662.             current->AreaData.OriginStr = (UBYTE)value;
  1663.          }
  1664.       }
  1665.  
  1666.    DropASem();
  1667.  
  1668.    if (titel)
  1669.       SysMsg(NO_AREAS_FOUND);
  1670.  
  1671.    return TRUE;
  1672.    }
  1673.  
  1674. ///
  1675.  
  1676. /// "TakeASem"
  1677.  
  1678. VOID TakeASem(BOOL exclusive)
  1679.    {
  1680.    if (exclusive)
  1681.       ObtainSemaphore(&KMSBase->AreaSem);
  1682.    else
  1683.       ObtainSemaphoreShared(&KMSBase->AreaSem);
  1684.    }
  1685.  
  1686. ///
  1687.  
  1688. /// "DropASem"
  1689.  
  1690. VOID DropASem(VOID)
  1691.    {
  1692.    ReleaseSemaphore(&KMSBase->AreaSem);
  1693.    }
  1694.  
  1695. ///
  1696.